package repository

import (
	"context"
	"webook/internal/domain"
	"webook/internal/repository/cache"
)

type RankingRepository interface {
	ReplaceTopN(ctx context.Context, arts []domain.Article) error
	GetTopN(ctx context.Context) ([]domain.Article, error)
	UpdateLoadStatus(ctx context.Context, name string, load int32) error
	GetMinLoadPod(ctx context.Context) ([]string, int32, error)
}

type CachedRankingRepository struct {
	//只有redis缓存
	cache cache.RankingCache

	// 下面是给 v1 用的 redis和本地缓存
	redisCache *cache.RankingRedisCache
	localCache *cache.RankingLocalCache
}

func (repo *CachedRankingRepository) GetMinLoadPod(ctx context.Context) ([]string, int32, error) {
	return repo.cache.GetMinLoadPod(ctx)
}

func (repo *CachedRankingRepository) UpdateLoadStatus(ctx context.Context, name string, load int32) error {
	return repo.cache.SetLoadStatus(ctx, name, load)
}

func (repo *CachedRankingRepository) GetTopN(ctx context.Context) ([]domain.Article, error) {
	return repo.cache.Get(ctx)
}
func (repo *CachedRankingRepository) ReplaceTopN(ctx context.Context, arts []domain.Article) error {
	return repo.cache.Set(ctx, arts)
}

func NewCachedRankingRepository(cache cache.RankingCache) RankingRepository {
	return &CachedRankingRepository{cache: cache}
}

// 同时有本地缓存和redis缓存
func NewCachedRankingRepositoryV1(redisCache *cache.RankingRedisCache, localCache *cache.RankingLocalCache) *CachedRankingRepository {
	return &CachedRankingRepository{redisCache: redisCache, localCache: localCache}
}

/*
强制使用本地缓存的漏洞：如果一个节点刚发起来，此时本地缓存里没有数据，redis也崩溃的话，无法获取到榜单数据
可以走一个failover容错策略，前端获取不到信息时，再请求一次
*/
func (repo *CachedRankingRepository) GetTopNV1(ctx context.Context) ([]domain.Article, error) {
	res, err := repo.localCache.Get(ctx)
	if err == nil { //本地缓存里有的话直接返回
		return res, nil
	}
	res, err = repo.redisCache.Get(ctx)
	if err != nil { //读取redis缓存失败 强制从本地缓存里取 无需检查本地缓存是否过期 作为兜底策略
		return repo.localCache.ForceGet(ctx)
	}
	_ = repo.localCache.Set(ctx, res) //从redis缓存里取出来后放入本地缓存
	return res, nil
}
func (repo *CachedRankingRepository) ReplaceTopNV1(ctx context.Context, arts []domain.Article) error {
	//先放本地缓存 再放redis缓存
	_ = repo.localCache.Set(ctx, arts)
	return repo.redisCache.Set(ctx, arts)
}
